/*
Kakine
ActionScript Framework
Copyright © 2011, PUNY, LLC.

This file is part of KAKINE.

KAKINE is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

KAKINE is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with KAKINE.  If not, see <http://www.gnu.org/licenses/>.
*/ 
package com.puny.mvc.views.singleviews
{
	import com.puny.mvc.helpers.FrameHelper;
	import com.puny.mvc.helpers.IHelper;
	import com.puny.mvc.models.EntityModels;
	import com.puny.mvc.models.Model;
	
	import flash.display.MovieClip;
	import flash.display.Shape;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Rectangle;
	
	/**
	 * Dispatched when this view is clicked  
	 * @eventType com.puny.mvc.views.View.CLICKED
	 */
	[Event(name="clicked", type="com.puny.mvc.views.ButtonView")]
	
	/**
	 * $Revision: 753 $<br/>
	 * RichButtonView<br/>
	 * This view can have the only one asset.
	 * This class can handle animations, such as opening, roll over/out, click, and closing.
	 */
	public class RichButtonView extends RichView
	{

		private var _cover:Shape;
		private var _bigTarget:Boolean = true;
		private var _later:MouseEvent = null;
		private var _lockClickAnimation:Boolean = true;
		private var _immediately:Boolean = true;
		private var _currentLabel:String = OUT;
		private var _clicked:Event = new Event(CLICKED);
		private var _helper:IHelper;
		
		/**
		 * 
		 * @param name a swf file name, a MovieClipAsset instance, or a Class name
		 * @param exprotedName an exproted asset name
		 */
		public function RichButtonView(src:Object,exportedName:String)
		{
			super(src,exportedName);
		}
				
		/**
		 * If <code>true</code> (default), the hit area become a rectangle which surrounds the button shape.
		 * Otherwise, the hit area should be the shape of button.
		 */
		public function set bigTarget(value:Boolean):void {
			if (value) {
				if (_cover != null) {
					_mc.removeChild(_cover);
				}				
				coverWithRectangle();
			} else {
				if (_cover != null) {
					_mc.removeChild(_cover);
				}				
			}
			_bigTarget = value;
		}
		
		/**
		 * If <code>true</code> (default), an animation labeled, <code>CLICK</code>, must paly at the end.
		 * After the animation finishes, the latest one of <code>mouseUp</code>,<code>mouseDown</code>,
		 * <code>rollOver</code>, and <code>rollOut</code> will be handled only if it's fired during the animation.
		 * Otherwise, the animation will be treated as the other animation.
		 */
		public function set lockClickAnimation(value:Boolean):void {
			_lockClickAnimation = value;
		}
		
		/**
		 * If <code>true</code> (default), <code>CLICKED</code> event will be dispatched immediately.
		 * Otherwise, it will be dispatched after the <code>CLICK</code> animation finishes.
		 */
		public function set immediately(value:Boolean):void {
			_immediately = value;
		}
				
		/**
		 * Wrap up opening animation
		 */
		override public function afterOpen():void {
			//put button attributes
			if (_bigTarget) {
				coverWithRectangle();
			}
			addButtonListeners(_mc, _immediately? dispacthHandler:null);
		}
		
		private function coverWithRectangle():void {
			if (_mc != null) {
				var bound:Rectangle = _mc.getBounds(this);
				_cover = new Shape();
				_cover.graphics.beginFill(0xFFFFFF,0);
				_cover.graphics.drawRect(bound.x,bound.y,_mc.width,_mc.height);
				_cover.graphics.endFill();
				_mc.addChild(_cover);
				_mc.cacheAsBitmap = false;
			}
		}
		
		/**
		 * Handle button animatoin
		 * 
		 * @return <code>MovieClip</code> object
		 */
		override protected function buttonEventHandler(event:MouseEvent):MovieClip {
			var result:Boolean = false;

			if( _lockClickAnimation && _mc.currentLabel == CLICK ) {
				_later = event;
				result = true;
			} else {
				var state:Model = EntityModels.getInstance(event.type);
				result = setupAnimation(state.label,state.goal);
			}

			if (result) {
				return event.currentTarget as MovieClip;
			} else {
				if (_helper != null) {
					_helper.cancel();
				}
				return super.buttonEventHandler(event);
			}
		}
		
		private function setupAnimation(label:String,goal:String):Boolean {
			if (_mc[label]) {
				trace(label+":", _mc.name);
				_helper = FrameHelper.setup(this,
								  function():void {animationInitializer(label);},
								  function():Boolean {return animation(label, goal);},
								  null);
				return true;
			}
			return false;
		}
		
		private function animationInitializer(label:String):void {
			trace("Button animation:", label+", was initialized.");
			_currentLabel = _mc.currentLabel;
			_mc.initializing = true;
			gotoAndPlay(label);
		}
		
		private function animation(label:String,goal:String):Boolean {
			if (_mc == null) {
				return false;
			}
			var ret:Boolean = (_mc.currentLabel == label);
			if (!ret) {
				//the animation must end because ...
				if (_mc.initializing) {
					//another animation started.
					trace("Button animation:", label+", was interrupted.");
				} else {
					//it reaches at the end frame.
					trace("Button animation:", label+", reaches at its end and stops at a frame,", goal+".");
					if (!gotoAndStop(goal)) {
						trace("But the label,", goal+", is missing.");
						gotoAndStop(_currentLabel);
					}
				}
				
				if (goal == CLICKED) {
					//click animation ends.
					if(!_immediately) {
						dispacthHandler();
					}
					if(_later != null) {
						trace("A delayed event,", _later.type+ ", starts.");
						buttonEventHandler(_later);
						_later = null;
					}
				}
			}
			_mc.initializing = false;
			//if returns true, the animation keeps going.
			return ret;
		}

		/**
		 * play closing animation.
		 */		
		override public function beforeClose():void {
			if (_helper != null) {
				_helper.skip();
			}
			removeButtonListeners(_mc);
			_mc.initializing = true;
			super.beforeClose();
		}
		
		override public function afterClose():void {
			_cover = null;
			_clicked = null;
			super.afterClose();
			_helper = null;
		}
		
		private function dispacthHandler(event:Event=null):void {
			trace(CLICKED,"event was fired in", exportedName+"("+_mc.name+")");
			dispatchEvent(_clicked.clone());
		}
		
	}
}